package spring_learn.a04;


import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.env.StandardEnvironment;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


/**
 * AutowiredAnnotationBeanPostProcessor运行分析
 */
@SpringBootApplication
public class AutoWiredTest {

    public static void main(String[] args) throws Throwable {
        DefaultListableBeanFactory defaultListableBeanFactory=new DefaultListableBeanFactory();
        defaultListableBeanFactory.registerSingleton("bean2",new Bean2());
        defaultListableBeanFactory.registerSingleton("bean3",new Bean3());

        //解析value注解
        defaultListableBeanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        //解析${}
        defaultListableBeanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);

        AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor=
                new AutowiredAnnotationBeanPostProcessor();
        autowiredAnnotationBeanPostProcessor.setBeanFactory(defaultListableBeanFactory);
        Bean1 bean1=new Bean1();
        System.out.println(bean1);
        //解析autowired和value注解
        //Bean1{bean2=spring_learn.a04.Bean2@5a8e6209, bean3=null, home='${JAVA_HOME}'}
        //autowiredAnnotationBeanPostProcessor.postProcessProperties(null,bean1,"bean1");
        System.out.println(bean1);

        // 这里在模拟上述postProcessProperties方法的实现
        Method findAutowiringMetadata = autowiredAnnotationBeanPostProcessor.getClass().
                getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
        findAutowiringMetadata.setAccessible(true);
        //通过findAutowiringMetadata这个方法找到bean1中所有被autowired/value注解的方法/属性，封装成injectionMetadata
        InjectionMetadata injectionMetadata  = (InjectionMetadata)findAutowiringMetadata.
                invoke(autowiredAnnotationBeanPostProcessor, "bean1", Bean1.class, null);
        System.out.println(injectionMetadata);
        //进行注入，使value和autowired注解生效
        //按类型查找值
        injectionMetadata.inject(bean1,"bean1",null);
        //Bean1{bean2=spring_learn.a04.Bean2@2b9627bc, bean3=null, home='${JAVA_HOME}'}
        System.out.println(bean1);

        //如何按类型查找值？
        //封装成DependencyDescriptor对象，然后使用beanfactory通过这个对象查找对应的bean

        Field bean3 = Bean1.class.getDeclaredField("bean3");
        DependencyDescriptor dd1 = new DependencyDescriptor(bean3,false);
        Object o = defaultListableBeanFactory.resolveDependency(dd1, null, null, null);
        System.out.println(o);

        Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
        DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
        Object o1 = defaultListableBeanFactory.resolveDependency(dd2, null, null, null);
        System.out.println(o1);


        Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
        DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true);
        Object o2 = defaultListableBeanFactory.resolveDependency(dd3, null, null, null);
        System.out.println(o2);

    }
}
